package com.unitd.logistics.comm.plugins.generator;

import com.google.common.collect.Maps;
import com.unitd.logistics.comm.utils.DateUtils;
import com.unitd.logistics.comm.utils.StringUtils;
import freemarker.template.Template;
import lombok.Data;

import java.io.*;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.util.*;

/**
 * 代码生成器
 * 此类里面的生成代码路径需要根据实际情况进行相应的更改
 * 后续有时间再讲相应的生成代码路径配置到配置文件中，通过读取配置文件属性来指定
 *
 * @author Hudan
 * @version 1.0
 * @filename CodeGenerateUtils.java
 * @copyright www.pactera.com
 * @date 18-8-29
 */
@Data
public class CodeGenerateUtils {

    private String dtoFilePath;
    private String consumerFilePath;
    private String providerFilePath;
    private String resourceFilePath;
    private String testFilePath;
    private String packageName;
    private String sonPackageName;
    private String tableName;
    private String tableDesc;
    private String className;
    private String author;
    private String driver;
    private String url;
    private String user;
    private String password;
    private String currDate = DateUtils.format2DateStr(new Date(), "yyyy-MM-dd");

    /**
     * 构造方法
     */
    public CodeGenerateUtils(String dtoFilePath, String consumerFilePath, String providerFilePath, String resourceFilePath, String testFilePath,
                             String packageName, String sonPackageName, String tableName, String tableDesc, String className, String author,
                             String driver, String url, String user, String password) {
        this.dtoFilePath = dtoFilePath;
        this.consumerFilePath = consumerFilePath;
        this.providerFilePath = providerFilePath;
        this.resourceFilePath = resourceFilePath;
        this.testFilePath = testFilePath;
        this.packageName = packageName;
        this.sonPackageName = sonPackageName;
        this.tableName = tableName;
        this.tableDesc = tableDesc;
        this.className = className;
        this.author = author;
        this.driver = driver;
        this.url = url;
        this.user = user;
        this.password = password;
    }

    /**
     * 获取数据库连接
     *
     * @return 数据库连接对象
     */
    public Connection getConnection() throws Exception {
        Class.forName(driver);
        Properties props = new Properties();
        props.put("user", user);
        props.put("password", password);
        // Oracle在通过jdbc连接的时候需要添加一个参数来设置是否获取注释
        props.put("remarksReporting", "true");
        return DriverManager.getConnection(url, props);
    }

    public void generate() {
        try {
            Connection connection = getConnection();
            DatabaseMetaData databaseMetaData = connection.getMetaData();
            ResultSet resultSet = databaseMetaData.getColumns(null, "%", tableName, "%");

            List<ColumnClass> columnClassList = new ArrayList<>();
            ColumnClass columnClass;
            String columnName;
            while (resultSet.next()) {
                // 列名
                columnName = resultSet.getString("COLUMN_NAME");

                //id、create_time、update_time 字段略过
                if (columnName.toLowerCase().equals("id")) {
                    continue;
                }
//                if (columnName.toLowerCase().equals("created_by")) {
//                    continue;
//                }
//                if (columnName.toLowerCase().equals("creator")) {
//                    continue;
//                }
//                if (columnName.toLowerCase().equals("created_date")) {
//                    continue;
//                }
//
//                if (columnName.toLowerCase().equals("last_modified_by")) {
//                    continue;
//                }
//                if (columnName.toLowerCase().equals("modifier")) {
//                    continue;
//                }
//                if (columnName.toLowerCase().equals("last_modified_date")) {
//                    continue;
//                }
//
//                if (columnName.toLowerCase().equals("is_deleted")) {
//                    continue;
//                }
//                if (columnName.toLowerCase().equals("remark")) {
//                    continue;
//                }

                columnClass = new ColumnClass();
                //获取字段名称
                columnClass.setColumnName(columnName);
                //获取字段类型
                columnClass.setColumnType(resultSet.getString("TYPE_NAME"));
                //转换字段名称，如 sys_name 变成 SysName
                columnClass.setChangeColumnName(StringUtils.toCamelCase(columnName));
                //字段在数据库的注释
                columnClass.setColumnComment(resultSet.getString("REMARKS"));
                columnClassList.add(columnClass);
            }
            Map<String, Object> dataMap = Maps.newHashMap();
            dataMap.put("model_column", columnClassList);
//
//            // 生成实体DTO类
//            generateDTOFile(resultSet, dataMap);

//            // 生成实体Entity类
//            generateModelFile(resultSet, dataMap);
//            // 生成Mapper文件
//            generateMapperFile(resultSet, dataMap);
//            // 生成Dao文件
//            generateDaoFile(resultSet);

            // 生成服务层接口文件
            generateServiceFile(resultSet);
            // 生成服务实现层文件
            generateServiceImplFile(resultSet);
//
//            // 生成Provider的Controller层文件
//            generateProviderControllerFile(resultSet);
//            // 生成Consumer的Controller层文件
//            generateConsumerControllerFile(resultSet);

            // 生成单元测试类
            generateTestFile(resultSet, dataMap);
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {

        }
    }

    /**
     * 生成实体类类
     *
     * @param resultSet
     * @param dataMap
     * @throws Exception
     */
    private void generateModelFile(ResultSet resultSet, Map<String, Object> dataMap) throws Exception {
        final String suffix = ".java";
        final String path = dtoFilePath + packageName.replace(".", "/") + "/modules/model/pojo/po/" + className + suffix;
        final String templateName = "Model.ftl";

        File mapperFile = new File(path);
        if (!mapperFile.getParentFile().exists()) {
            mapperFile.getParentFile().mkdirs();
        }

        generateFileByTemplate(templateName, mapperFile, dataMap);
    }

    /**
     * 生成DTO类
     *
     * @param resultSet
     * @param dataMap
     * @throws Exception
     */
    private void generateDTOFile(ResultSet resultSet, Map<String, Object> dataMap) throws Exception {
        final String suffix = "Bo.java";
        final String path = dtoFilePath + packageName.replace(".", "/") + "/modules/model/pojo/dto/" + sonPackageName + className + suffix;
        final String templateName = "DTO.ftl";

        File mapperFile = new File(path);
        if (!mapperFile.getParentFile().exists()) {
            mapperFile.getParentFile().mkdirs();
        }

        generateFileByTemplate(templateName, mapperFile, dataMap);
    }

    /**
     * 生成Mapper类
     *
     * @param resultSet
     * @throws Exception
     */
    private void generateDaoFile(ResultSet resultSet) throws Exception {
        final String suffix = "Mapper.java";
        final String path = providerFilePath + packageName.replace(".", "/") + "/modules/model//" + sonPackageName + "/com/base/cloud/edu/pay/mapper/" + className + suffix;
        final String templateName = "Dao.ftl";

        generateFileByTemplate(templateName, path);
    }

    /**
     * 生成Mapper类
     *
     * @param resultSet
     * @param dataMap
     * @throws Exception
     */
    private void generateMapperFile(ResultSet resultSet, Map<String, Object> dataMap) throws Exception {
        final String suffix = "Mapper.xml";
        final String path = resourceFilePath + packageName.replace(".", "/") + "/edu/" + sonPackageName + "/com/base/cloud/edu/pay/mapper/" + className + suffix;
        final String templateName = "Mapper.ftl";

        File mapperFile = new File(path);
        if (!mapperFile.getParentFile().exists()) {
            mapperFile.getParentFile().mkdirs();
        }

        generateFileByTemplate(templateName, mapperFile, dataMap);
    }

    /**
     * 生成Service接口类
     *
     * @param resultSet
     * @throws Exception
     */
    private void generateServiceFile(ResultSet resultSet) throws Exception {
        final String suffix = "Service.java";
        final String path = providerFilePath + packageName.replace(".", "/") + "/edu/" + sonPackageName + "/service/" + className + suffix;
        final String templateName = "Service.ftl";

        generateFileByTemplate(templateName, path);
    }

    /**
     * 生成ServiceImpl接口实现类
     *
     * @param resultSet
     * @throws Exception
     */
    private void generateServiceImplFile(ResultSet resultSet) throws Exception {
        final String suffix = "ServiceImpl.java";
        final String path = providerFilePath + packageName.replace(".", "/") + "/edu/" + sonPackageName + "/service/impl/" + className + suffix;
        final String templateName = "ServiceImpl.ftl";

        generateFileByTemplate(templateName, path);
    }

    /**
     * 生成Provider的Controller类
     *
     * @param resultSet
     * @throws Exception
     */
    private void generateProviderControllerFile(ResultSet resultSet) throws Exception {
        final String suffix = "Provider.java";
        final String path = providerFilePath + packageName.replace(".", "/") + "/edu/" + sonPackageName + "/provider/" + className + suffix;
        final String templateName = "Provider.ftl";

        generateFileByTemplate(templateName, path);
    }

    /**
     * 生成Consumer的Controller类
     *
     * @param resultSet
     * @throws Exception
     */
    private void generateConsumerControllerFile(ResultSet resultSet) throws Exception {
        final String suffix = "Controller.java";
        final String path = consumerFilePath + packageName.replace(".", "/") + "/edu/" + sonPackageName + "/controller/" + className + suffix;
        final String templateName = "Consumer.ftl";

        generateFileByTemplate(templateName, path);
    }

    /**
     * 生成单元测试类
     *
     * @param resultSet
     */
    private void generateTestFile(ResultSet resultSet, Map<String, Object> dataMap) throws Exception {
        final String prefix = "Test";
        final String path = testFilePath + packageName.replace(".", "/") + "/edu/" + sonPackageName + "/com/base/cloud/edu/pay/mapper/" + prefix + className + ".java";
        final String templateName = "Test.ftl";

        File mapperFile = new File(path);
        if (!mapperFile.getParentFile().exists()) {
            mapperFile.getParentFile().mkdirs();
        }

        generateFileByTemplate(templateName, mapperFile, dataMap);
    }

    /**
     * 根据模板文件生成相应的代码文件
     *
     * @param templateName 模板文件名称
     * @param path         需要生成的目标文件全路径
     */
    private void generateFileByTemplate(String templateName, String path) throws Exception {
        File mapperFile = new File(path);

        if (!mapperFile.getParentFile().exists()) {
            mapperFile.getParentFile().mkdirs();
        }
        Map<String, Object> dataMap = Maps.newHashMap();
        generateFileByTemplate(templateName, mapperFile, dataMap);
    }

    /**
     * 真正根据freemark模板生成代码的地方
     *
     * @param templateName 模板文件名称
     * @param file         需要生成的目标文件全路径
     * @param dataMap      参数集合
     * @throws Exception
     */
    private void generateFileByTemplate(final String templateName, File file, Map<String, Object> dataMap) throws Exception {
        Template template = FreeMarkerTemplateUtils.getTemplate(templateName);
        FileOutputStream fos = new FileOutputStream(file);
        dataMap.put("tableName", tableName);
        dataMap.put("tableDesc", tableDesc);
        dataMap.put("packageName", packageName);
        dataMap.put("sonPackageName", sonPackageName);
        dataMap.put("className", className);
        dataMap.put("author", author);
        dataMap.put("date", currDate);
        Writer out = new BufferedWriter(new OutputStreamWriter(fos, "utf-8"), 10240);
        template.process(dataMap, out);
    }
}